package com.topisv.tms.service.work.ExceptionOrder;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.AreaGroup;
import com.topisv.tms.entity.CusStockMerge;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.EdiOrderItem;
import com.topisv.tms.entity.QcConfig;
import com.topisv.tms.entity.QueryParamHolder;
import com.topisv.tms.entity.User;
import com.topisv.tms.entity.log.OrderLog;
import com.topisv.tms.entity.stock.instorage.InstorageBill;
import com.topisv.tms.entity.stock.instorage.InstorageCountItem;
import com.topisv.tms.entity.stock.instorage.InstorageUpDispatchSubTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpDispatchTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpSubTaskItem;
import com.topisv.tms.entity.stock.instorage.InstorageUpTask;
import com.topisv.tms.entity.work.WorkOrder;
import com.topisv.tms.entity.work.ExceptionOrder.ExceptionBackItem;
import com.topisv.tms.entity.work.ExceptionOrder.ExceptionOrder;
import com.topisv.tms.repository.AreaGroupDao;
import com.topisv.tms.repository.CusStockMergeDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.EdiOrderDao;
import com.topisv.tms.repository.EdiOrderItemDao;
import com.topisv.tms.repository.QcConfigDao;
import com.topisv.tms.repository.UserDao;
import com.topisv.tms.repository.log.OrderLogDao;
import com.topisv.tms.repository.stock.instorage.InstorageBillDao;
import com.topisv.tms.repository.stock.instorage.InstorageCountItemDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchSubTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchSubTaskItemDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpTaskDao;
import com.topisv.tms.repository.work.WorkOrderDao;
import com.topisv.tms.repository.work.ExceptionOrder.ExceptionBackItemDao;
import com.topisv.tms.repository.work.ExceptionOrder.ExceptionOrderDao;
import com.topisv.tms.service.EdiOrderService;
import com.topisv.tms.service.account.ShiroDbRealm.ShiroUser;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.tools.StringCusUtils;
import com.topisv.tms.utils.EdiOrderUtil;
import com.topisv.tms.utils.enums.StatusEnums;
import com.topisv.tms.utils.rule.TMSTransportRule;

import net.sf.json.JSONArray;

/**
 * 异常单_service
 * @author ch
 */
@Component
@Transactional(readOnly = true)
public class ExceptionOrderService extends BaseService{

	@Autowired
	private ExceptionOrderDao exceptionOrderDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private WorkOrderDao workOrderDao;
	@Autowired
	private AreaGroupDao areaGroupDao;
	@Autowired
	private OrderLogDao orderLogDao;
	@Autowired
	private ExceptionBackItemDao exceptionBackItemDao;
	@Autowired
	private InstorageBillDao instorageBillDao;
	@Autowired
	private InstorageUpTaskDao instorageUpTaskDao;
	@Autowired
	private InstorageCountItemDao instorageCountItemDao;
	@Autowired
	private EdiOrderDao ediOrderDao;
	@Autowired
	private EdiOrderItemDao ediOrderItemDao;
	@Autowired
	private CustomersDao customersDao;
	@Autowired
	private CusStockMergeDao cusStockMergeDao;
	@Autowired
	private EdiOrderService ediOrderService;
	@Autowired
	private InstorageUpDispatchTaskDao instorageUpDispatchTaskDao;
	@Autowired
	private InstorageUpDispatchSubTaskDao instorageUpDispatchSubTaskDao;
	@Autowired
	private InstorageUpDispatchSubTaskItemDao instorageUpDispatchSubTaskItemDao;
	@PersistenceContext
    private EntityManager em;
	@Autowired
	private QcConfigDao qcConfigDao;
	@Autowired
	private EdiGoodsSkuDao  ediGoodsSkuDao;
	
	/**
	 * 分页查询
	 * @param param
	 * @param pageNumber
	 * @param pageSize
	 * @return
	 */
	public Page<ExceptionOrder> loadPageByParam(Map<String, Object> param,int pageNumber, int pageSize) {
		Sort sort = new Sort(Sort.Direction.DESC,"id");
	    PageRequest pageRequest = new PageRequest(pageNumber-1, pageSize, sort);
	    Specification<ExceptionOrder> spec =this.getWhereClause(param);
	    Page<ExceptionOrder> page = this.exceptionOrderDao.findAll(spec, pageRequest);
	    List<ExceptionOrder> orderList=page.getContent();
	    for (ExceptionOrder o : orderList) {
			User user=this.userDao.findByJobuuid(o.getCreaterUuid());
            o.setCreater(user);
			
			WorkOrder order=this.workOrderDao.loadByOrderno(o.getOrderno());
			o.setOrder(order);
			
			if(order!=null){
				AreaGroup warehouse=this.areaGroupDao.findByGroupCode(order.getWarehouseCode());
				o.setWarehouse(warehouse);
			}
		}
	    return page;
	}
	
	public Page<ExceptionOrder> loadPageByParam(QueryParamHolder paramHolder) {
		Specification<ExceptionOrder> spec = getWhereClause(paramHolder.getSearchParams());
		Page<ExceptionOrder> page = findByJson(paramHolder, exceptionOrderDao, spec, ExceptionOrder.class);
		List<ExceptionOrder> orderList = page.getContent();
		for (ExceptionOrder o : orderList) {
			User user = this.userDao.findByJobuuid(o.getCreaterUuid());
			o.setCreater(user);

			WorkOrder order = this.workOrderDao.loadByOrderno(o.getOrderno());
			o.setOrder(order);

			if (order != null) {
				AreaGroup warehouse = this.areaGroupDao.findByGroupCode(order.getWarehouseCode());
				o.setWarehouse(warehouse);
			}
		}
		return page;
	}
	/**
	 * 查询
	 * @param param
	 * @return
	 */
	public List<ExceptionOrder> loadByParam(Map<String, Object> param) {
		Specification<ExceptionOrder> spec = getWhereClause(param);
		List<ExceptionOrder> orderList = this.exceptionOrderDao.findAll(spec);
		for (ExceptionOrder o : orderList) {
			User user=this.userDao.findByJobuuid(o.getCreaterUuid());
            o.setCreater(user);
			
			WorkOrder order=this.workOrderDao.loadByOrdernoOrCustomerorderno(o.getOrderno());
			o.setOrder(order);
			
			if(order!=null){
				AreaGroup warehouse=this.areaGroupDao.findByGroupCode(order.getWarehouseCode());
				o.setWarehouse(warehouse);
			}
			
		}
		return orderList;
	}
	
	/**
	 * 查询条件封装
	 * @param searchParams
	 * @return
	 */
	private Specification<ExceptionOrder> getWhereClause(final Map<String, Object> searchParams) {
		return new Specification<ExceptionOrder>(){
		    @Override
		    public Predicate toPredicate(Root<ExceptionOrder> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
		      Predicate pre = cb.conjunction();
		      
		      
		      //customerCodes
		      String customerCodes=(String) searchParams.get("customerCodes");
		      if(StringUtils.isNotBlank(customerCodes)) {
		    	  String[] customerCodeSplit = customerCodes.split(":");
				  ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
				  int i = 0;
				  for (String _customerCode : customerCodeSplit) {
					 tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("customerCode"), _customerCode);
					 i++;
				  }
				  pre.getExpressions().add(cb.or(tempCustomerCode));
		      }
			  
		      //areagroups
		      String areagroups=(String) searchParams.get("areagroups");
		      if(StringUtils.isNotBlank(areagroups)) {
		    	  String[] areagroupSplit = areagroups.split(":");
				  ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
				  int j = 0;
				  for (String _areagroup : areagroupSplit) {
						areagroupArray[j] = (ComparisonPredicate) cb.equal(r.get("warehouseCode"), _areagroup);
						j++;
				  }
				  pre.getExpressions().add(cb.or(areagroupArray));
			  }
		      
		      
		      String orderno=(String) searchParams.get("orderno");
		      if(StringUtils.isNotBlank(orderno)){
					pre.getExpressions().add(cb.like(r.<String>get("orderno"),"%"+orderno.trim()+"%"));
			  }
		      
		      //订单号或者快递单号
		      String allOrderno=(String) searchParams.get("allOrderno");
		      if(StringUtils.isNotBlank(allOrderno)){
					pre.getExpressions().add(
							cb.or(
									cb.like(r.<String>get("orderno"),"%"+allOrderno.trim()+"%"),
									cb.like(r.<String>get("customerOrderno"),"%"+allOrderno.trim()+"%"),
									cb.like(r.<String>get("fromOrderno"),"%"+allOrderno.trim()+"%"),
									cb.like(r.<String>get("expressNo"),"%"+allOrderno.trim()+"%")
							));
			  }
		      
		      String customerOrderno=(String) searchParams.get("customerOrderno");
		      if(StringUtils.isNotBlank(customerOrderno)){
					pre.getExpressions().add(cb.like(r.<String>get("customerOrderno"),"%"+customerOrderno.trim()+"%"));
			  }	
		      
		      //exceptionType
		      String exceptionType=(String) searchParams.get("exceptionType");
		      if(StringUtils.isNotBlank(exceptionType)){
		    	  if("back".equals(exceptionType)){ //包含拒收单，换货单,取消单
		    		  pre.getExpressions().add(
	    				  cb.or(
	    						  cb.equal(r.get("exceptionType"),"refuse"),
	    						  cb.equal(r.get("exceptionType"),"change"),
	    						  cb.equal(r.get("exceptionType"),"outScope"),
	    						  cb.equal(r.get("exceptionType"),"lose"),
	    						  cb.and(
	    								  cb.equal(r.get("exceptionType"),"cancel"), 
	    								  cb.equal(r.get("cancelStatus"),"pass")
	    							   ),
    							   cb.and(
 	    								  cb.equal(r.get("exceptionType"),"cancel"), 
 	    								  cb.equal(r.get("cancelStatus"),"stop")
 	    							   )
	    				  ));
		    	  }else{
		    		  pre.getExpressions().add(cb.equal(r.get("exceptionType"),exceptionType));
		    	  }
			  }	
		      
		      Object fromDate=  searchParams.get("fromDate1");
		      if (fromDate != null) {
		        pre.getExpressions().add(cb.greaterThanOrEqualTo(r.<Date>get("createTime"), (Date)fromDate));
		      }
		      
		      Object toDate=searchParams.get("toDate1");
		      if (toDate != null) {
		        pre.getExpressions().add(cb.lessThanOrEqualTo(r.<Date>get("createTime"), (Date)toDate));
		      }
		      
		      return pre;
		    }
		  };
       }

	/**
	 * 拦截标识
	 * @param orderno
	 * @param jobuuid 
	 * @param flag pass:拦截失败 stop:拦截成功
	 * @return success： 标识成功   error:标识失败
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public String cancelFlag(String orderno, String jobuuid, String flag) throws Exception {
		try {

			ExceptionOrder eOrder = this.exceptionOrderDao.loadByOrderno(orderno);

			if (eOrder == null) {
				return "error";
			}

			String cancelStatus = eOrder.getCancelStatus();
			if ("stop".equals(cancelStatus) || "pass".equals(cancelStatus)) {
				return "error";
			}

			ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User curUser = this.userDao.findOne(user.id);
			Date now = new Date();

			String operateType = "";
			String aboutInfo = "";

			if ("stop".equals(flag)) { // 拦截成功
				
				 /***begin bug531 by zhangweize**/
				//质检配置信息 bug531 by zhangweize
				QcConfig qcConfig = qcConfigDao.queryQcConfigByWarehouseCode(eOrder.getWarehouseCode());
				
				//检查订单明细中的SKU是否需要进批次、保质期管理, 不需要，生成上架单；需要则进行质检
				List<Object[]> skuList = ediGoodsSkuDao.checkSKUShelf_lifeOrBatch(eOrder.getOrderno());
		       
				
				// (质检配置信息不能为空并且状态等于1）并且 sku不需要进批次、保质期管理
				if ((qcConfig != null && "1".equals(qcConfig.getStatus())) && (skuList == null || skuList.isEmpty())) {

					if (StringUtils.isBlank(eOrder.getBackStatus())) {

						// 生成上架单
						crateInstorageUpTask(eOrder, curUser);

						// 修改exceptionOrder 退回状态 wait:登记待退 receive:已收货质检 in:已入库
						eOrder.setBackStatus("in");
						operateType = "16";
						aboutInfo = curUser.getRealname() + "拦截成功，完成质检，入库";

					} else {
						throw new RuntimeException("退回状态已更改，请刷新页面");
					}
				} else {

					// 质检标志,进行质检
					eOrder.setBackStatus("receive");

					operateType = "12";
					aboutInfo = curUser.getRealname() + "拦截标识(拦截成功)";

				}

			} else if ("pass".equals(flag)) { // 拦截失败

				eOrder.setBackStatus("wait");// 等待追回

				operateType = "12";
				aboutInfo = curUser.getRealname() + "拦截标识(拦截失败)";

			}

			// 修改exceptionOrder 取消状态
			eOrder.setCancelStatus(flag);
			
			
			
			exceptionOrderDao.save(eOrder);

			// 订单日志
			OrderLog orderLog = new OrderLog(eOrder.getOrderno(), eOrder.getCustomerCode(), operateType, curUser, now,
					null, aboutInfo);

			/***end bug531 by zhangweize**/
			
			this.orderLogDao.save(orderLog);
			return "success";

		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 登记异常单
	 * @param orderno
	 * @param exceptionType
	 * @param jobuuid
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public String regist(String orderno, String exceptionType, String mark,String jobuuid) throws Exception {
		String msg="success";
		try {
			
			ExceptionOrder eOrder=this.exceptionOrderDao.loadByAnyOrderno(orderno);
			if(eOrder!=null){
				msg="registed"; //已经登记
				return msg;
			}
			
			WorkOrder workOrder=this.workOrderDao.loadByAnyOrderno(orderno);
			String status=workOrder.getStatus();
			if(! "6".equals(status)){ 
				msg="unSended";  //没有发货，不能登记如下异常单：（拒收，换货，丢件）
				return msg;
			}
			
			//设置异常类型
			workOrder.setCancelStatus(exceptionType);
			this.workOrderDao.save(workOrder);
			
			//创建异常单
			Date now=new Date();
			eOrder=new ExceptionOrder();
			eOrder.setExceptionType(exceptionType);
			eOrder.setCustomerCode(workOrder.getCustomerCode());
			eOrder.setWarehouseCode(workOrder.getWarehouseCode());
			eOrder.setOrderno(workOrder.getOrder().getOrdeno());
			eOrder.setCustomerOrderno(workOrder.getCustomerOrderno());
			eOrder.setFromOrderno(workOrder.getFromno());
			eOrder.setExpressNo( (StringUtils.isBlank(workOrder.getExpressNo())?"":workOrder.getExpressNo()) + 
					             (StringUtils.isBlank(workOrder.getEbillNo())?"":workOrder.getEbillNo() )  );
			eOrder.setCreaterUuid(jobuuid);
			eOrder.setCreateTime(now);
			eOrder.setRecallFlag("unrecall");
			eOrder.setMark(mark);
			String backReason="";
			if( "refuse".equals(exceptionType) ){ //拒收
				eOrder.setBackStatus("wait");
				backReason="拒收";
			}else if("change".equals(exceptionType)){ //换货
				eOrder.setBackStatus("wait");
				backReason="换货";
			}else if("outScope".equals(exceptionType)){ //超区
				eOrder.setBackStatus("wait");
				backReason="超区";
			}else if("lose".equals(exceptionType)){ //丢件
				backReason="丢件";
			}
			this.exceptionOrderDao.save(eOrder);
			
			//添加订单日志
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User user=this.userDao.findOne(curUser.id);
			OrderLog orderlog=new OrderLog(eOrder.getOrderno(),
					eOrder.getCustomerCode(), 
					"17", 
					user,
					now,
					null, 
					user.getRealname()+"登记异常单（"+backReason+"）");
			this.orderLogDao.save(orderlog);
			
			return msg;
			
		} catch (Exception e) {
			throw e;
		}
		
		
	}

	/**
	 * 退回件收货
	 * @param exceptionOrderId
	 * @param jobuuid
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public String receive(Long exceptionOrderId, String jobuuid) throws Exception {
		String msg="success";
		try {
			
			ExceptionOrder eOrder=this.exceptionOrderDao.findOne(exceptionOrderId);
			String backStatus=eOrder.getBackStatus();
			if(!"wait".equals(backStatus)){
				msg="nostatus"; //不在收货状态
				return msg;
			}
			
			//设置收货状态
			eOrder.setBackStatus("receive");
			this.exceptionOrderDao.save(eOrder);
			
			
			//添加订单日志
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User user=this.userDao.findOne(curUser.id);
			Date now=new Date();
			OrderLog orderlog=new OrderLog(eOrder.getOrderno(),
					eOrder.getCustomerCode(), 
					"14", 
					user,
					now,
					null, 
					user.getRealname()+"收货确认");
			this.orderLogDao.save(orderlog);
			
			
			return msg;
			
		} catch (Exception e) {
			throw e;
		}
		
	}

	/**
	 * 查询
	 * @param exceptionId
	 * @return
	 */
	public ExceptionOrder loadById(Long exceptionId) {
		return this.exceptionOrderDao.findOne(exceptionId);
	}

	/**
	 * 完成质检
	 * @param exceptionId
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public String finishQc(Long exceptionId) throws Exception {
		try {
			
			ExceptionOrder eOrder=this.exceptionOrderDao.findOne(exceptionId);
			String backStatus=eOrder.getBackStatus();
			if("cancel".equals(eOrder.getExceptionType())){
				List<EdiOrderItem> items = ediOrderItemDao.findByOrdeno(eOrder.getOrderno());
				List<ExceptionBackItem> eItems = exceptionBackItemDao.loadByExceptionId(exceptionId);
				Map<String, Integer> map1 = EdiOrderUtil.countEdiOrderItem(items);
				Map<String, Integer> map2 = EdiOrderUtil.countExceptionItem(eItems);
				if (!EdiOrderUtil.checkCountNumMatch(map1, map2)) {
					return "notMatch";
				}
			}
			if("receive".equals(backStatus)){ 
				eOrder.setBackStatus("qc"); //设置为已质检
				
				//添加订单日志
				ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
				User user=this.userDao.findOne(curUser.id);
				Date now=new Date();
				OrderLog orderlog=new OrderLog(eOrder.getOrderno(),
						eOrder.getCustomerCode(), 
						"15", 
						user,
						now,
						null, 
						user.getRealname()+"完成退回件质检");
				this.orderLogDao.save(orderlog);
			}
			
		} catch (Exception e) {
			log.error("error", e);
			throw e;
		}
		return "success";
	}

	/**
	 * 退回件入库
	 * @param exceptionOrderId
	 * @param jobuuid
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public String backin(Long exceptionOrderId, String jobuuid) throws Exception {
		String msg="success";
		try {
			
			ExceptionOrder eOrder=this.exceptionOrderDao.findOne(exceptionOrderId);
			String backStatus=eOrder.getBackStatus();
			if(!"qc".equals(backStatus)){
				msg="nostatus"; //不在入库状态
				return msg;
			}
			
			//设置入库状态
			eOrder.setBackStatus("in");
			this.exceptionOrderDao.save(eOrder);
			
			
			//添加订单日志
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User user=this.userDao.findOne(curUser.id);
			Date now=new Date();
			OrderLog orderlog=new OrderLog(eOrder.getOrderno(),
					eOrder.getCustomerCode(), 
					"16", 
					user,
					now,
					null, 
					user.getRealname()+"放入待上架区");
			this.orderLogDao.save(orderlog);
			
			
			return msg;
			
		} catch (Exception e) {
			
			throw e;
		}
	}

	/**
	 * 创建退回入库单
	 * @param customerCode
	 * @param warehouseCode
	 * @param exceptionIdJsonArray
	 * @param jobuuid
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String createInBill(String customerCode, String warehouseCode,JSONArray exceptionIdArray, String jobuuid) throws Exception {
		String msg="success";
		try {
			
			Integer skuNum_error=0;
			Integer goodsNum_error=0;
			
			Integer skuNum_noterror=0;
			Integer goodsNum_noterror=0;
			
			StringBuilder aboutCodeStr_error=new StringBuilder();
			StringBuilder aboutCodeStr_noterror=new StringBuilder();
			
			List<ExceptionBackItem> allItemList=new ArrayList<ExceptionBackItem>();
			
			String instorageBillCode_error="";
			String instorageBillCode_noterror="";
			
			//统计sku
			Map<String, Integer> skuMap_noterror=new HashMap<String, Integer>();
			Map<String, Integer> skuMap_error=new HashMap<String, Integer>();
			
			for (Object exceptionId : exceptionIdArray) {
				Long _exceptionId=Long.valueOf(exceptionId+"");
				ExceptionOrder eOrder=this.exceptionOrderDao.findOne(_exceptionId);
				if(eOrder==null || !"qc".equals(eOrder.getBackStatus())){ //不在入仓状态
					return "nostatus";
//					throw new Exception("退回单不在入仓状态，订单号："+eOrder.getOrderno());
				}
				
				List<ExceptionBackItem> itemList=this.exceptionBackItemDao.loadByExceptionId(_exceptionId);
				allItemList.addAll(itemList);
				String sku;
				Integer num;
				String batchCode;
				String productDate;
				String expireDate;
				String errorFlag;
				for (ExceptionBackItem item : itemList) {
					sku=item.getSku();
					batchCode = StringCusUtils.TransNull(item.getBatchCode());
					productDate = StringCusUtils.TransNull(item.getProductDate());
					expireDate = StringCusUtils.TransNull(item.getExpireDate());
					num=item.getNum();
					errorFlag=item.getErrorFlag();
					
					String key = sku + "_" + batchCode + "_" + productDate + "_" + expireDate;
					
					if("error".equals(errorFlag)){ //报损件
						if(skuMap_error.keySet().contains(key)){
							skuMap_error.put(key, skuMap_error.get(key)+num);
						}else{
							skuMap_error.put(key, num);
							skuNum_error++;
						}
						goodsNum_error+=num;
						
						//相关号码
						if(aboutCodeStr_error.indexOf(eOrder.getOrderno())<0){
							if(aboutCodeStr_error.length()==0){
								aboutCodeStr_error.append(eOrder.getOrderno());
							}else{
								aboutCodeStr_error.append(";"+eOrder.getOrderno());
							}
							
						}
						
					}else if("noterror".equals(errorFlag)){ //正常件
						if(skuMap_noterror.keySet().contains(key)){
							skuMap_noterror.put(key, skuMap_noterror.get(key)+num);
						}else{
							skuMap_noterror.put(key, num);
							skuNum_noterror++;
						}
						goodsNum_noterror+=num;
						
						//相关号码
						if(aboutCodeStr_noterror.indexOf(eOrder.getOrderno())<0){
							if(aboutCodeStr_noterror.length()==0){
								aboutCodeStr_noterror.append(eOrder.getOrderno());
							}else{
								aboutCodeStr_noterror.append(";"+eOrder.getOrderno());
							}
						}
					}
					
				}
				
				//修改exceptionOrder状态为：已入仓
				eOrder.setBackStatus("in");
				this.exceptionOrderDao.save(eOrder);
				
				//添加订单日志
				ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
				User user=this.userDao.findOne(curUser.id);
				Date now=new Date();
				OrderLog orderlog=new OrderLog(eOrder.getOrderno(),
						eOrder.getCustomerCode(), 
						"16", 
						user,
						now,
						null, 
						user.getRealname()+"创建入库上架任务。");
				this.orderLogDao.save(orderlog);
			}
			
			
			//创建正常入库信息
			if(!skuMap_noterror.isEmpty()){
				Date now=new Date();
				//创建入库单
				InstorageBill bill=new InstorageBill();
				bill.setBillType("returnOrder"); //入库单类型 (customer. 采购入库 allot.调拨入库 cancelOrder.取消单入库   returnOrder：退回件入库)
				instorageBillCode_noterror=TMSTransportRule.generateInStorageBillCode();
				bill.setBillCode(instorageBillCode_noterror);
				bill.setAboutCode(aboutCodeStr_noterror.toString());;//相关单号 （订单号序列）
				bill.setCustomerCode(customerCode);//商户信息
				bill.setInwarehouseCode(warehouseCode);//入库仓库信息
				bill.setSkuNum(skuNum_noterror);
				bill.setGoodsNum(goodsNum_noterror);
				bill.setRemarks("退回单完好件入库");//备注
				bill.setCreateTime(now);//入库时间
				bill.setErrorFlag("noterror");
				bill.setStatus("3");//入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
				bill.setCreaterUuid(jobuuid);
				this.instorageBillDao.save(bill);
				
				//生成上架分配任务
				InstorageUpDispatchTask disTask = new InstorageUpDispatchTask();
				disTask.setInstorageBill(bill);
				disTask.setWorkerUuid(jobuuid);
				disTask.setStatus("2");//0:未处理 1:已领取 2:已分配
				disTask.setTaskCode(TMSTransportRule.generateDispatchTaskCode());
				instorageUpDispatchTaskDao.save(disTask);
				
				//新增分配任务
				InstorageUpDispatchSubTask subTask = new InstorageUpDispatchSubTask();
				subTask.setSubTaskCode(TMSTransportRule.generateDispatchSubTaskCode());
				subTask.setTaskCode(disTask.getTaskCode());
				instorageUpDispatchSubTaskDao.save(subTask);
				
				//创建分配任务明细
				for(String key:skuMap_noterror.keySet()){
				    String skuInfo[] = key.split("_", -1);
	        		InstorageUpSubTaskItem taskItem = new InstorageUpSubTaskItem();
	        		taskItem.setTaskCode(disTask.getTaskCode());
	        		taskItem.setSubTaskCode(subTask.getSubTaskCode());
	        		taskItem.setSkuCode(skuInfo[0]);
	        		taskItem.setBatchCode(skuInfo[1]);
	        		taskItem.setProductDate(skuInfo[2]);
	        		taskItem.setExpireDate(skuInfo[3]);
					int num=skuMap_noterror.get(key);
					taskItem.setNum(num);
					taskItem.setErrorFlag("noterror");
					instorageUpDispatchSubTaskItemDao.save(taskItem);
	        	}
				//创建上架任务
				InstorageUpTask upTask=new InstorageUpTask();
	        	upTask.setBillCode(bill.getBillCode());
	        	upTask.setCreateTime(now);
	        	upTask.setCustomerCode(bill.getCustomerCode());
	        	upTask.setStatus("undo");
	        	upTask.setTaskCode(TMSTransportRule.generateUpTaskCode());
	        	upTask.setSubTaskCode(subTask.getSubTaskCode());
	        	upTask.setTaskType("single");
	        	upTask.setWarehouseCode(bill.getInwarehouseCode());
	        	upTask.setErrorFlag("noterror");
	        	this.instorageUpTaskDao.save(upTask);
	        	
	        	
	        	
	        	//创建点收明细
	        	int _num;
	        	List<InstorageCountItem> coutItemList=new ArrayList<InstorageCountItem>();
	        	for(String key:skuMap_noterror.keySet()){
	        	    String skuInfo[] = key.split("_",-1);
	        		_num=skuMap_noterror.get(key);
	        		InstorageCountItem countItem=new InstorageCountItem();
	        		countItem.setBillCode(bill.getBillCode());
	        		countItem.setCustomerCode(customerCode);
	        		countItem.setInstorageType("single");
	        		countItem.setNum(_num);
	        		countItem.setSku(skuInfo[0]);
	        		countItem.setBatchCode(skuInfo[1]);
	        		countItem.setProductDate(skuInfo[2]);
	        		countItem.setExpireDate(skuInfo[3]);
	        		countItem.setUpStatus("unup");
	        		countItem.setUpNum(0);
	        		countItem.setUptaskCode(upTask.getTaskCode());
//	        		countItem.setTaskCode(taskCode);
	        		countItem.setWarehouseCode(warehouseCode);
	        		countItem.setErrorFlag("noterror");
	        		coutItemList.add(countItem);
	        	}
	        	this.instorageCountItemDao.save(coutItemList);
			}
			
			
			//创建报损入库信息
			if(!skuMap_error.isEmpty()){
				//创建入库单
				InstorageBill bill=new InstorageBill();
				Date now=new Date();
				bill.setBillType("returnOrder"); //入库单类型 (customer. 采购入库 allot.调拨入库 cancelOrder.取消单入库   returnOrder：退回件入库)
				instorageBillCode_error=TMSTransportRule.generateInStorageBillCode();
				bill.setBillCode(instorageBillCode_error); //入库单号(编码规则：'RK'+时间,例如：RK201309091212004 )
				bill.setAboutCode(aboutCodeStr_noterror.toString());;//相关单号 （订单号序列）
				bill.setCustomerCode(customerCode);//商户信息
				bill.setInwarehouseCode(warehouseCode);//入库仓库信息
				bill.setSkuNum(skuNum_error);
				bill.setGoodsNum(goodsNum_error);
				bill.setRemarks("退回单报损入库");//备注
				bill.setCreateTime(now);//入库时间
				bill.setErrorFlag("error");
				bill.setStatus("3");//入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
				bill.setCreaterUuid(jobuuid);
				this.instorageBillDao.save(bill);
				//生成上架分配任务
				InstorageUpDispatchTask disTask = new InstorageUpDispatchTask();
				disTask.setInstorageBill(bill);
				disTask.setWorkerUuid(jobuuid);
				disTask.setStatus("2");//0:未处理 1:已领取 2:已分配
				disTask.setTaskCode(TMSTransportRule.generateDispatchTaskCode());
				instorageUpDispatchTaskDao.save(disTask);
				
				//新增分配任务
				InstorageUpDispatchSubTask subTask = new InstorageUpDispatchSubTask();
				subTask.setSubTaskCode(TMSTransportRule.generateDispatchSubTaskCode());
				subTask.setTaskCode(disTask.getTaskCode());
				instorageUpDispatchSubTaskDao.save(subTask);
				
				//创建分配任务明细
				for(String key:skuMap_error.keySet()){
				    String skuInfo[] = key.split("_", -1);
	        		InstorageUpSubTaskItem taskItem = new InstorageUpSubTaskItem();
	        		taskItem.setTaskCode(disTask.getTaskCode());
	        		taskItem.setSubTaskCode(subTask.getSubTaskCode());
	        		taskItem.setSkuCode(skuInfo[0]);
	        		taskItem.setBatchCode(skuInfo[1]);
	        		taskItem.setProductDate(skuInfo[2]);
	        		taskItem.setExpireDate(skuInfo[3]);
					int num=skuMap_error.get(key);
					taskItem.setNum(num);
					taskItem.setErrorFlag("error");
					instorageUpDispatchSubTaskItemDao.save(taskItem);
	        	}
				//创建上架任务
				InstorageUpTask upTask=new InstorageUpTask();
	        	upTask.setBillCode(bill.getBillCode());
	        	upTask.setCreateTime(now);
	        	upTask.setCustomerCode(bill.getCustomerCode());
	        	upTask.setStatus("undo");
	        	upTask.setTaskCode(TMSTransportRule.generateUpTaskCode());
	        	upTask.setSubTaskCode(subTask.getSubTaskCode());
	        	upTask.setTaskType("single");
	        	upTask.setWarehouseCode(bill.getInwarehouseCode());
	        	upTask.setErrorFlag("error");
	        	this.instorageUpTaskDao.save(upTask);
	        	
	        	//创建点收明细
	        	int _num;
	        	List<InstorageCountItem> coutItemList=new ArrayList<InstorageCountItem>();
	        	for(String key:skuMap_error.keySet()){
	        	    String skuInfo[] = key.split("_", -1);
	        		_num=skuMap_error.get(key);
	        		InstorageCountItem countItem=new InstorageCountItem();
	        		countItem.setBillCode(bill.getBillCode());
	        		countItem.setCustomerCode(customerCode);
	        		countItem.setInstorageType("single");
	        		countItem.setNum(_num);
	        		countItem.setSku(skuInfo[0]);
	        		countItem.setBatchCode(skuInfo[1]);
	        		countItem.setProductDate(skuInfo[2]);
	        		countItem.setExpireDate(skuInfo[3]);
	        		countItem.setUpStatus("unup");
	        		countItem.setUpNum(0);
//	        		countItem.setTaskCode(taskCode);
	        		countItem.setUptaskCode(upTask.getTaskCode());
	        		countItem.setWarehouseCode(warehouseCode);
	        		countItem.setErrorFlag("error");
	        		coutItemList.add(countItem);
	        	}
	        	this.instorageCountItemDao.save(coutItemList);
			}
			
			
			//设置退回件明细的属性：入库单号
			String errorFlag;
			for(ExceptionBackItem backItem: allItemList){
				errorFlag=backItem.getErrorFlag();
				if("error".equals(errorFlag)){
					backItem.setInstorageBillCode(instorageBillCode_error);
				}else if("noterror".equals(errorFlag)){
					backItem.setInstorageBillCode(instorageBillCode_noterror);
				}
			}
			this.exceptionBackItemDao.save(allItemList);
			
			return msg;
		} catch (Exception e) {
			
			throw e;
		}
	}

	/**
	 * 重发订单
	 * @param infoMap 
	 * @param exceptionId 异常单ID
	 * @param companyCode 快递公司
	 * @param recena 收件人姓名
	 * @param mobile 收件人固定电话
	 * @param teleph 收件人移动电话
	 * @param addres 收件人地址
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public String recall(Map<String, Integer> infoMap,Long exceptionId,String companyCode,
			String recena,String mobile,String teleph,String addres) throws Exception {
		String msg="success";
		try {
			Date now=new Date();
			ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User curUser=this.userDao.findOne(user.id);
			
			ExceptionOrder eOrder=this.exceptionOrderDao.findOne(exceptionId);
			EdiOrder ediOrder_old=this.ediOrderDao.findByOrdeno(eOrder.getOrderno());
			List<EdiOrderItem> orderItems = ediOrderItemDao.findByOrdeno(eOrder.getOrderno());
			ediOrder_old.setSkulst(orderItems);
			//校验库存
			Customers customers=customersDao.findByCustomerCode(ediOrder_old.getCustomerCode());
			//限制订单流入
			if ("1".equals(customers.getPlaceStatus())) {
				Map<String, Integer> maps = ediOrderService.setCusStock(ediOrder_old);
				if (maps == null) {
					//没有找到合适的库存
					return "stockNotEnough";
				}
			}
			
			//创建新的订单信息
			EdiOrder ediOrder_new=(EdiOrder) ediOrder_old.clone();
			ediOrder_new.setId(null);
			ediOrder_new.setRecena(recena);
			ediOrder_new.setTeleph(teleph);
			ediOrder_new.setMobile(mobile);
			ediOrder_new.setCacode(companyCode);
			ediOrder_new.setOldCacode(companyCode);
			ediOrder_new.setAddres(addres);
			String orderno_new=ediOrder_old.getOrdeno()+"R";
			ediOrder_new.setOrdeno(orderno_new);
			ediOrder_new.setOrderStatus("ok");
			ediOrder_new.setStatus("pending");
			ediOrder_new.setCrtime(new Date());
			ediOrder_new.setBackupTaskCode(null);
			ediOrder_new.setBatchTaskCode(null);
			this.ediOrderDao.save(ediOrder_new);
			
			//保存商品信息
			
			Integer totalQty = 0;
			for(String sku: infoMap.keySet()){
				Integer qty=infoMap.get(sku);
				totalQty += qty;
				EdiOrderItem item=new EdiOrderItem();
				item.setOrdeno(orderno_new);
				item.setSku(sku);
				item.setQty(qty);
				item.setCustomerCode(ediOrder_old.getCustomerCode());
				EdiOrderItem oldEdiOrderItem = findOrderItem(orderItems, sku);
				if (oldEdiOrderItem != null) {
					item.setLineNo(oldEdiOrderItem.getLineNo());
					item.setSellFlg(oldEdiOrderItem.getSellFlg());
					item.setNam(oldEdiOrderItem.getNam());
					item.setCrtime(now);
					item.setPri(oldEdiOrderItem.getPri());
					item.setAmo(oldEdiOrderItem.getAmo());
					item.setVol(oldEdiOrderItem.getVol());
					item.setDes(oldEdiOrderItem.getDes());
				}
				//保证数据一致，重发时，相当于重新流入订单,此时应预定库存数量。
				if ("1".equals(customers.getPlaceStatus())) {
					CusStockMerge cusStockMerge= cusStockMergeDao.findCustomerWarSku(ediOrder_new.getCustomerCode(), ediOrder_new.getWarehouseCode(), item.getSku());
					cusStockMerge.setOrderNum(cusStockMerge.getOrderNum()+qty);
					this.cusStockMergeDao.save(cusStockMerge);
				}
				
				this.ediOrderItemDao.save(item);
			}
			ediOrder_new.setOrderType(totalQty > 1 ? StatusEnums.ORDER_TYPE_MULTIPLE.getStatus() : StatusEnums.ORDER_TYPE_SINGLE.getStatus());
			//修改异常单状态：已重发
			eOrder.setRecallFlag("recall");
			this.exceptionOrderDao.save(eOrder);
				
			//写日志
			OrderLog log=new OrderLog(
					ediOrder_old.getOrdeno(),
					ediOrder_old.getCustomerCode(),
					"11", //操作类型 （1.创建批次 2.创建任务 3.拣货完成 4.包装完成 5.发货完成 6.签收完成 7.异常登记 8.完成灯光拣选任务 9.打印单据 10.取消单 11.异常单重发 12.取消单拦截标识 13.创建退回单 14.退回单收货 15.退回单质检 16.退回单入库）
					curUser,
					now,
					null,
					user.getRealname()+"重发异常单（新订单号："+ediOrder_new.getOrdeno()+"）");
			this.orderLogDao.save(log);
			
			//写日志
			OrderLog log1=new OrderLog(
					ediOrder_new.getOrdeno(),
					ediOrder_new.getCustomerCode(),
					"11", //操作类型 （1.创建批次 2.创建任务 3.拣货完成 4.包装完成 5.发货完成 6.签收完成 7.异常登记 8.完成灯光拣选任务 9.打印单据 10.取消单 11.异常单重发 12.取消单拦截标识 13.创建退回单 14.退回单收货 15.退回单质检 16.退回单入库）
					curUser,
					now,
					null,
					user.getRealname()+"创建重发单（原订单号："+ediOrder_old.getOrdeno()+"）");
			this.orderLogDao.save(log1);
			
			
			return msg;
			
		} catch (Exception e) {
			
			throw e;
		}
	}
	
	private EdiOrderItem findOrderItem(List<EdiOrderItem> orderItems,String sku){
		for (EdiOrderItem ediOrderItem : orderItems) {
			if (sku.equals(ediOrderItem.getSku())) {
				return ediOrderItem;
			}
		}
		return null;
	}
	
	public List<ExceptionOrder> findCancelOrder(Map<String, Object> map){
		Specification<ExceptionOrder> spec = getWhereClause(map);
		List<ExceptionOrder> cancelOrderList = exceptionOrderDao.findAll(spec);
		return cancelOrderList;
	}

	/**
	 * 取消单导出 数据查询  2016-06-13 lianghe.yuan
	 * @param paramMap 查询参数
	 * @return 数据集合
	 */
	@SuppressWarnings("unchecked")
    public List<Object[]> findCancelOrderNew(Map<String, String> paramMap){
	    //构建SQL
        StringBuffer sql = new StringBuffer("SELECT ");
        //列
        sql.append(" CASE a.exception_type ")
            .append(" WHEN 'cancel' THEN '取消单' ")
            .append(" WHEN 'refuse' THEN '拒收单' ")
            .append(" WHEN 'change' THEN '换货单' ")
            .append(" WHEN 'outScope' THEN '超区单' ")
            .append(" WHEN 'lose' THEN '丢件单' ")
            .append(" WHEN null THEN '空值' ")
            .append(" ELSE CONCAT('未知类型', a.exception_type) ")
            .append(" END 类型, ")
            .append(" c.customer_name 商家, ")
            .append(" d.group_name 仓库, ")
            .append(" a.orderno 订单编号, ")
            .append(" a.customer_orderno 客户订单号, ")
            .append(" a.from_orderno 来源订单号, ")
            .append(" a.express_no 运单号, ")
            .append(" e.realname 创建人, ")
            .append(" DATE_FORMAT(a.create_time, '%Y/%m/%d') 创建时间, ")
            .append(" CASE b.status  ")
            .append("   WHEN '0' THEN '待创建批次' ")
            .append("   WHEN '1' THEN '创建批次' ")
            .append("   WHEN '2' THEN '创建任务' ")
            .append("   WHEN '3' THEN '已拣货' ")
            .append("   WHEN '4' THEN '已灯光拣选' ")
            .append("   WHEN '5' THEN '已包装' ")
            .append("   WHEN '6' THEN '已发货' ")
            .append("   WHEN '9' THEN '待包装' ")
            .append("   ELSE CONCAT('未知状态:', b.status) ")
            .append(" END 状态, ")
            .append(" b.invoice_no 发票号, ")
            .append(" CASE b.guarantee_status WHEN '1' THEN '是' ELSE '否' END 是否打印保修单 ")
            .append(",f.caname 快递公司, f.provna 省, b.weight 商品重量, f.sku_qty 发货数量, g.info 商品名称") //add LiBin 20160914 增加导出信息
            ;
        //表
        sql.append(" FROM exception_order a ")
        	.append(" LEFT JOIN work_order b ON b.orderno=a.orderno ")
        	.append(" LEFT JOIN customers c ON c.customer_code=a.customer_code ")
        	.append(" LEFT JOIN pms_areagroup d ON d.group_code=a.warehouse_code ")
        	.append(" LEFT JOIN tbl_user e ON e.jobuuid=a.creater_uuid")
        	.append(" LEFT JOIN edi_order f on f.ordeno = a.orderno ")
        	.append(" LEFT JOIN (select GROUP_CONCAT(nam,':',qty) as info ,ordeno from edi_order_item group by ordeno) g on g.ordeno=f.ordeno ") //add LiBin 20160914 增加导出信息
        	;
        
        //条件 
        sql.append(" WHERE 1=1 ");

        String fromDate             = paramMap.get("fromDate");
        String toDate                 = paramMap.get("toDate");
        String exceptionType      = paramMap.get("exceptionType");
        String allOrderno           = paramMap.get("allOrderno");
        String customerCode      = paramMap.get("customerCodes");
        String warehouseCode   = paramMap.get("areagroups");
        
        if (StringUtils.isNotBlank(fromDate))              sql.append(" AND a.create_time >= ? ");
        if (StringUtils.isNotBlank(toDate))                  sql.append(" AND a.create_time <= ? ");
        
        if (StringUtils.isNotBlank(exceptionType)) {
            if ("back".equals(exceptionType)) {
                sql.append(" AND (a.exception_type = ? ");
                sql.append(" OR a.exception_type = ? ");
                sql.append(" OR a.exception_type = ? ");
                sql.append(" OR a.exception_type = ? ");
                sql.append(" OR ( a.exception_type = ? and a.cancel_status = ?) ");
                sql.append(" OR ( a.exception_type = ? and a.cancel_status = ?)  ");
                sql.append(" ) ");
            } else {
                sql.append(" AND a.exception_type = ? ");
            }
        }
        
        if (StringUtils.isNotBlank(allOrderno)) {
            sql.append("AND (a.orderno LIKE ? ");
            sql.append("OR a.customer_orderno LIKE ? ");
            sql.append("OR a.from_orderno LIKE ? ");
            sql.append("OR a.express_no LIKE ? )");
        }
        
        if (StringUtils.isNotBlank(customerCode))      sql.append(" AND a.customer_code in (:customerCodeList) ");
        if (StringUtils.isNotBlank(warehouseCode))    sql.append(" AND a.warehouse_code in (:warehouseCodeList) ");
        
        //参数
        Query query = em.createNativeQuery(sql.toString());
        
        int i = 1;
        if (StringUtils.isNotBlank(fromDate)) query.setParameter(i++, fromDate);
        if (StringUtils.isNotBlank(toDate)) query.setParameter(i++, toDate);
        
        if (StringUtils.isNotBlank(exceptionType)) {
            if ("back".equals(exceptionType)) {
                query.setParameter(i++, "refuse");
                query.setParameter(i++, "change");
                query.setParameter(i++, "outScope");
                query.setParameter(i++, "lose");
                query.setParameter(i++, "cancel");
                query.setParameter(i++, "pass");
                query.setParameter(i++, "cancel");
                query.setParameter(i++, "stop");
            } else {
                query.setParameter(i++, exceptionType);
            }
        }
        
        if (StringUtils.isNotBlank(allOrderno)) {
            query.setParameter(i++, "%" + allOrderno.trim() + "%");
            query.setParameter(i++, "%" + allOrderno.trim() + "%");
            query.setParameter(i++, "%" + allOrderno.trim() + "%");
            query.setParameter(i++, "%" + allOrderno.trim() + "%");
        }
        
        if (StringUtils.isNotBlank(customerCode)) {
            String[] customerCodeList = customerCode.split(":");
            ((org.hibernate.ejb.HibernateQuery) query).getHibernateQuery().setParameterList("customerCodeList", customerCodeList);
        }
        
        if (StringUtils.isNotBlank(warehouseCode)) {
            String[] warehouseCodeList = warehouseCode.split(":");
            ((org.hibernate.ejb.HibernateQuery) query).getHibernateQuery().setParameterList("warehouseCodeList", warehouseCodeList);
        }
        
	    return query.getResultList();
	}
    
    /**
     * 创建上架任务
     * 
     *
     * @param eOrder [参数说明]
     * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
     * @version 1.0.0
     */
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void crateInstorageUpTask(ExceptionOrder eOrder, User curUser) throws Exception{
    	Long exceptionId = eOrder.getId();
        String orderno = eOrder.getOrderno();
        String jobuuid = curUser.getJobuuid();
		List<ExceptionBackItem> exceptionBackItemList = new ArrayList<>();

		Date now=new Date();

		Integer skuNum_noterror = 0;
		Integer goodsNum_noterror = 0;

		// 统计sku
		Map<String, Integer> skuMap_noterror = new HashMap<String, Integer>();
		StringBuilder aboutCodeStr_noterror = new StringBuilder();

		// 查询订单明细
		List<Object[]> itemsQtyList = ediOrderItemDao.queryOrdernosQty(orderno);

		// 查询订单明细不能为空
		if (itemsQtyList != null && !itemsQtyList.isEmpty()) {
			for (Object[] itemsQtyArry : itemsQtyList) {
				ExceptionBackItem exceptionBackItem = new ExceptionBackItem();
				exceptionBackItem.setErrorFlag("noterror");
				exceptionBackItem.setSku(itemsQtyArry[0].toString());
				exceptionBackItem.setNum(Integer.valueOf(itemsQtyArry[1].toString()));
				exceptionBackItem.setOrderno(orderno);
				exceptionBackItem.setExceptionId(exceptionId);
				exceptionBackItemList.add(exceptionBackItem);
			}

			for (ExceptionBackItem item : exceptionBackItemList) {
				String sku = item.getSku();
				Integer num = item.getNum();
				String errorFlag = item.getErrorFlag();
				if ("noterror".equals(errorFlag)) { // 正常件
					if (skuMap_noterror.keySet().contains(sku)) {
						skuMap_noterror.put(sku, skuMap_noterror.get(sku) + num);
					} else {
						skuMap_noterror.put(sku, num);
						skuNum_noterror++;
					}
					goodsNum_noterror += num;

					// 相关号码
					if (aboutCodeStr_noterror.indexOf(eOrder.getOrderno()) < 0) {
						if (aboutCodeStr_noterror.length() == 0) {
							aboutCodeStr_noterror.append(eOrder.getOrderno());
						} else {
							aboutCodeStr_noterror.append(";" + eOrder.getOrderno());
						}
					}
				}

			}

			String instorageBillCode_noterror = "";
			String warehouseCode = eOrder.getWarehouseCode();
			String customerCode = eOrder.getCustomerCode();

			// 创建正常入库信息
			if (!skuMap_noterror.isEmpty()) {
				
				// 创建入库单
				InstorageBill bill = new InstorageBill();
				bill.setBillType("returnOrder"); // 入库单类型 (customer.采购入库 allot.调拨入库 cancelOrder.取消单入库 returnOrder：退回件入库)
				instorageBillCode_noterror = TMSTransportRule.generateInStorageBillCode();
				bill.setBillCode(instorageBillCode_noterror);
				bill.setAboutCode(aboutCodeStr_noterror.toString());// 相关单号 （订单号序列）
				bill.setCustomerCode(customerCode);// 商户信息
				bill.setInwarehouseCode(warehouseCode);// 入库仓库信息
				bill.setSkuNum(skuNum_noterror);
				bill.setGoodsNum(goodsNum_noterror);
				bill.setRemarks("退回单完好件入库");// 备注
				bill.setCreateTime(now);// 入库时间
				bill.setErrorFlag("noterror");
				bill.setStatus("3");// 入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
				bill.setCreaterUuid(jobuuid);
				this.instorageBillDao.save(bill);

				// 生成上架分配任务
				InstorageUpDispatchTask disTask = new InstorageUpDispatchTask();
				disTask.setInstorageBill(bill);
				disTask.setWorkerUuid(jobuuid);
				disTask.setStatus("2");// 0:未处理 1:已领取 2:已分配
				disTask.setTaskCode(TMSTransportRule.generateDispatchTaskCode());
				instorageUpDispatchTaskDao.save(disTask);

				// 新增分配任务
				InstorageUpDispatchSubTask subTask = new InstorageUpDispatchSubTask();
				subTask.setSubTaskCode(TMSTransportRule.generateDispatchSubTaskCode());
				subTask.setTaskCode(disTask.getTaskCode());
				instorageUpDispatchSubTaskDao.save(subTask);

				// 创建分配任务明细
				for (String sku : skuMap_noterror.keySet()) {
					InstorageUpSubTaskItem taskItem = new InstorageUpSubTaskItem();
					taskItem.setTaskCode(disTask.getTaskCode());
					taskItem.setSubTaskCode(subTask.getSubTaskCode());
					taskItem.setSkuCode(sku);
					int num = skuMap_noterror.get(sku);
					taskItem.setNum(num);
					taskItem.setErrorFlag("noterror");
					instorageUpDispatchSubTaskItemDao.save(taskItem);
				}
				
				// 创建上架任务
				InstorageUpTask upTask = new InstorageUpTask();
				upTask.setBillCode(bill.getBillCode());
				upTask.setCreateTime(now);
				upTask.setCustomerCode(bill.getCustomerCode());
				upTask.setStatus("undo");
				upTask.setTaskCode(TMSTransportRule.generateUpTaskCode());
				upTask.setSubTaskCode(subTask.getSubTaskCode());
				upTask.setTaskType("single");
				upTask.setWarehouseCode(bill.getInwarehouseCode());
				upTask.setErrorFlag("noterror");
				this.instorageUpTaskDao.save(upTask);

				// 创建点收明细
				int _num;
				List<InstorageCountItem> coutItemList = new ArrayList<InstorageCountItem>();
				for (String sku : skuMap_noterror.keySet()) {
					_num = skuMap_noterror.get(sku);
					InstorageCountItem countItem = new InstorageCountItem();
					countItem.setBillCode(bill.getBillCode());
					countItem.setCustomerCode(customerCode);
					countItem.setInstorageType("single");
					countItem.setNum(_num);
					countItem.setSku(sku);
					countItem.setUpStatus("unup");
					countItem.setUpNum(0);
					countItem.setUptaskCode(upTask.getTaskCode());
					// countItem.setTaskCode(taskCode);
					countItem.setWarehouseCode(warehouseCode);
					countItem.setErrorFlag("noterror");
					coutItemList.add(countItem);
				}
				this.instorageCountItemDao.save(coutItemList);
			}

			// 设置退回件明细的属性：入库单号
			for (ExceptionBackItem backItem : exceptionBackItemList) {
				backItem.setInstorageBillCode(instorageBillCode_noterror);
			}
			this.exceptionBackItemDao.save(exceptionBackItemList);

		}else {
			throw new RuntimeException("订单明细为空"); 
		}
    }
}